/**
 * 格式化时间戳
 * 
 * @param {Number} timeStamp 传入的时间戳
 * @param {String} startType 要返回的时间字符串的格式类型：月M,分钟m
 * 如：yyyyMMdd,yyyy-MM-dd,yyyy-M-d,yyyy/MM/dd,yyyy/M/d,yyyy-MM,yyyy-M,yyyy年M月d日,yyyy年M月,M月d日
 * 如：yyyy-MM-dd hh:mm:ss,yyyy-MM-dd hh:mm,yyyy/MM/dd hh:mm:ss,yyyy年M月d日 h点m分s秒 
 * 也可以传\n\r等换行符
 * 注意：这里统一按24小时制,timeStamp可以是日期对象，也可以是时间戳,timeType可以不传
 */
export const formatDate = (timeStamp, timeType) => {
	//统一按24小时制
	const timeStampTypes = ['Date', 'String', 'Number']
	if (!timeStampTypes.includes(timeStamp.constructor.name)) {
		throw new Error(
			`Type check failed for argument "${timeStamp}".`
		)
	}
	const date =
		timeStamp instanceof Date ? timeStamp : new Date(+timeStamp)
	const format = {
		yyyy: date.getFullYear(),
		M: date.getMonth() + 1,
		d: date.getDate(),
		h: date.getHours(),
		m: date.getMinutes(),
		s: date.getSeconds(),
		MM: String(date.getMonth() + 1).padStart(2, '0'), //小于两位补零
		dd: String(date.getDate()).padStart(2, '0'),
		hh: String(date.getHours()).padStart(2, '0'),
		mm: String(date.getMinutes()).padStart(2, '0'),
		ss: String(date.getSeconds()).padStart(2, '0'),
		day: ['日', '一', '二', '三', '四', '五', '六'][date.getDay()],
	}
	let reformat = function(typeStr, str) {
		if (typeStr.includes(str) && typeStr.split(str).length - 1 == 1) {
			return typeStr.replace(str, format[str])
		} else {
			return typeStr
		}
	}

	let result
	for (let key in format) {
		result = reformat(result || timeType || 'yyyy-MM-dd', key)
	}
	return result
}

/**
 * 计算一个时间戳是现在时间节点的前多少时间段或后多少时间段
 * 
 * @param {String|Number} timeStamp 时间戳
 * @returns {String} 相对时间字符串
 */
export const getRelativeTime = timeStamp => {
	// 判断当前传入的时间戳是秒格式还是毫秒
	const IS_MILLISECOND = isMillisecond(timeStamp)
	// 如果是毫秒格式则转为秒格式
	if (IS_MILLISECOND) Math.floor(timeStamp /= 1000)
	// 传入的时间戳可以是数值或字符串类型，这里统一转为数值类型
	timeStamp = Number(timeStamp)
	// 获取当前时间时间戳
	const currentTime = Math.floor(Date.parse(new Date()) / 1000)
	// 判断传入时间戳是否早于当前时间戳
	const IS_EARLY = isEarly(timeStamp, currentTime)
	// 获取两个时间戳差值
	let diff = currentTime - timeStamp
	// 如果IS_EARLY为false则差值取反
	if (!IS_EARLY) diff = -diff
	let resStr = ''
	const dirStr = IS_EARLY ? '前' : '后'
	// 少于等于59秒
	if (diff <= 59) resStr = diff + '秒' + dirStr
	// 多于59秒，少于等于59分钟59秒
	else if (diff > 59 && diff <= 3599) resStr = Math.floor(diff / 60) + '分钟' + dirStr
	// 多于59分钟59秒，少于等于23小时59分钟59秒
	else if (diff > 3599 && diff <= 86399) resStr = Math.floor(diff / 3600) + '小时' + dirStr
	// 多于23小时59分钟59秒，少于等于29天59分钟59秒
	else if (diff > 86399 && diff <= 2623859) resStr = Math.floor(diff / 86400) + '天' + dirStr
	// 多于29天59分钟59秒，少于364天23小时59分钟59秒，且传入的时间戳早于当前
	else if (diff > 2623859 && diff <= 31567859 && IS_EARLY) resStr = getDate(timeStamp)
	else resStr = getDate(timeStamp, 'year')
	return resStr
}

/**
 * 返回指定长度的天数集合
 *
 * @param  {time} 时间
 * @param  {len} 长度
 * @param  {direction} 方向： 1: 前几天;  2: 后几天;  3:前后几天  默认 3
 * @return {Array} 数组
 *
 * @example date.getDays('2018-1-29', 6) // -> ["2018-1-26", "2018-1-27", "2018-1-28", "2018-1-29", "2018-1-30", "2018-1-31", "2018-2-1"]
 */
function getDays(time, len, diretion) {
	var tt = new Date(time)
	var getDay = function(day) {
		var t = new Date(time)
		t.setDate(t.getDate() + day)
		var m = t.getMonth() + 1
		return t.getFullYear() + '-' + m + '-' + t.getDate()
	}
	var arr = []
	if (diretion === 1) {
		for (var i = 1; i <= len; i++) {
			arr.unshift(getDay(-i))
		}
	} else if (diretion === 2) {
		for (var i = 1; i <= len; i++) {
			arr.push(getDay(i))
		}
	} else {
		for (var i = 1; i <= len; i++) {
			arr.unshift(getDay(-i))
		}
		arr.push(tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate())
		for (var i = 1; i <= len; i++) {
			arr.push(getDay(i))
		}
	}
	return diretion === 1 ? arr.concat([tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()]) :
		diretion === 2 ? [tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()].concat(arr) : arr
}

/**
 * 输入秒数返回时分秒
 * 
 * @param  {s} 秒数
 * @return {String} 字符串
 *
 * @example formatHMS(3610) // -> 1h0m10s
 */
function formatHMS(s) {
	var str = ''
	if (s > 3600) {
		str = Math.floor(s / 3600) + 'h' + Math.floor(s % 3600 / 60) + 'm' + s % 60 + 's'
	} else if (s > 60) {
		str = Math.floor(s / 60) + 'm' + s % 60 + 's'
	} else {
		str = s % 60 + 's'
	}
	return str
}


/*获取某月有多少天*/
function getMonthOfDay(time) {
	var date = new Date(time)
	var year = date.getFullYear()
	var mouth = date.getMonth() + 1
	var days

	//当月份为二月时，根据闰年还是非闰年判断天数
	if (mouth == 2) {
		days = (year % 4 == 0 && year % 100 == 0 && year % 400 == 0) || (year % 4 == 0 && year % 100 != 0) ? 28 : 29
	} else if (mouth == 1 || mouth == 3 || mouth == 5 || mouth == 7 || mouth == 8 || mouth == 10 || mouth == 12) {
		//月份为：1,3,5,7,8,10,12 时，为大月.则天数为31；
		days = 31
	} else {
		//其他月份，天数为：30.
		days = 30
	}
	return days
}

/*获取某年有多少天*/
function getYearOfDay(time) {
	var firstDayYear = new Date(time);
	firstDayYear.setMonth(0);
	firstDayYear.setDate(1)
	var lastDayYear = this.getLastDayOfYear(time);
	var numSecond = (new Date(lastDayYear).getTime() - new Date(firstDayYear).getTime()) / 1000;
	return Math.ceil(numSecond / (24 * 3600));
}

/*获取某年的第一天*/
function getFirstDayOfYear(time) {
	var year = new Date(time).getFullYear();
	return year + "-01-01 00:00:00";
}

/*获取某年最后一天*/
function getLastDayOfYear(time) {
	var year = new Date(time).getFullYear();
	var dateString = year + "-12-01 00:00:00";
	var endDay = this.getMonthOfDay(dateString);
	return year + "-12-" + endDay + " 23:59:59";
}

/*获取某个日期是当年中的第几天*/
function getDayOfYear(time) {
	var firstDayYear = new Date(time);
	firstDayYear.setMonth(0);
	firstDayYear.setDate(1)
	var numSecond = (new Date(time).getTime() - new Date(firstDayYear).getTime()) / 1000;
	return Math.ceil(numSecond / (24 * 3600));
}

/*获取某天是这一年的第几周*/
function getDayOfYearWeek(time) {
	var firstDayYear = new Date(time);
	firstDayYear.setMonth(0);
	firstDayYear.setDate(1) //某年第一天
	var firstDayWeek = new Date(firstDayYear).getDay() == 0 ? 7 : new Date(firstDayYear).getDay() //第一天是周几，0代表周日
	var computday = new Date(time);
	computday.setMonth(0);
	computday.setDate(8 - firstDayWeek); //从几号算起  	
	var numdays = (new Date(time).getTime() - new Date(computday).getTime()) / (24 * 3600 * 1000);
	return Math.ceil(numdays / 7) + 1;
}

/*获取今天是这一年的第几周*/
function getNowOfYearWeek() {
	var firstDayYear = new Date();
	firstDayYear.setMonth(0);
	firstDayYear.setDate(1) //某年第一天
	var firstDayWeek = new Date(firstDayYear).getDay() == 0 ? 7 : new Date(firstDayYear).getDay() //第一天是周几，0代表周日
	var computday = new Date();
	computday.setMonth(0);
	computday.setDate(8 - firstDayWeek); //从几号算起  	
	var numdays = (new Date().getTime() - new Date(computday).getTime()) / (24 * 3600 * 1000);
	return Math.ceil(numdays / 7) + 1;
}

//到某一个时间的倒计时
//getEndTime('2017/7/22 16:0:0')
//result："剩余时间6天 2小时 28 分钟20 秒"
//如果需要自动打印 可调用定时器
function getEndTime(endTime) {
	let startDate = new Date(); //开始时间，当前时间
	let endDate = new Date(endTime); //结束时间，需传入时间参数
	let t = endDate.getTime() - startDate.getTime(); //时间差的毫秒数
	let d = 0,
		h = 0,
		m = 0,
		s = 0;
	if (t >= 0) {
		d = Math.floor(t / 1000 / 3600 / 24);
		h = Math.floor(t / 1000 / 60 / 60 % 24);
		m = Math.floor(t / 1000 / 60 % 60);
		s = Math.floor(t / 1000 % 60);
	}
	return `剩余时间${d}天${h}小时${m}分钟${s}秒"`;
}

/* 倒计时（秒） */
const countdown = (duration, callback) => {
	let Timer = setTimeout(() => {
		duration--
		callback(duration)
		if (duration > 0) {
			countdown(duration, callback)
		} else {
			clearTimeout(Timer)
		}
	}, 1000)
}


//获取当前月份第一天
function getCurMonthFirstDay() {
	var date = new Date();
	date.setDate(1);
	var month = parseInt(date.getMonth() + 1);
	var day = date.getDate();
	if (month < 10) {
		month = '0' + month
	}
	if (day < 10) {
		day = '0' + day
	}
	return date.getFullYear() + '-' + month + '-' + day;
}

//获取当前月份最后一天
function getCurMonthLastDay() {
	var date = new Date();
	date.setDate(28) //防止2月是28天
	date.setMonth(date.getMonth() + 1);
	// 日期设置为0号, 0表示1号的前一天
	let lastDay = date.setDate(0);
	//月份
	var month = parseInt(date.getMonth() + 1);
	//天
	var day = new Date(lastDay).getDate();

	if (month < 10) {
		month = '0' + month
	}
	if (day < 10) {
		day = '0' + day
	}
	return date.getFullYear() + '-' + month + '-' + day;
}

// 获取某日期该月最后一天
// 示例：传入 "2025-03-01"，获取同格式的当月最后一天
// const dateString = "2025-03-01";
// const lastDay = getLastDayOfMonth(dateString);
// console.log(lastDay); // 输出: "2025-03-31"
function getLastDayOfMonth(dateString) {
	// 将日期字符串转换为 Date 对象
	const date = new Date(dateString);

	// 获取年份和月份
	const year = date.getFullYear();
	const month = date.getMonth() + 1; // 月份从 0 开始，所以需要加 1

	// 获取下个月的第一天
	const nextMonthFirstDay = new Date(year, month, 1);

	// 获取当前月份的最后一天
	const lastDayOfMonth = new Date(Number(nextMonthFirstDay) - 1);

	// 格式化最后一天为 "YYYY-MM-DD" 格式
	const lastDay = lastDayOfMonth.toISOString().split("T")[0];

	return lastDay;
}

// 获取本周的日历
function getWeekCalendar(startDate = new Date()) {
	// 获取当前日期是星期几（0表示星期天，6表示星期六）
	const dayOfWeek = startDate.getDay();

	// 计算本周的起始日期（星期一的日期）
	let startOfWeek = new Date(startDate);
	startOfWeek.setDate(startDate.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1));

	// 计算本周的结束日期（星期日的日期）
	let endOfWeek = new Date(startOfWeek);
	endOfWeek.setDate(startOfWeek.getDate() + 6);

	// 创建一个数组来保存本周的每一天
	const weekDays = [];
	for (let i = 0; i < 7; i++) {
		let day = new Date(startOfWeek);
		day.setDate(startOfWeek.getDate() + i);
		weekDays.push({
			date: day,
			dayOfWeek: day.getDay(),
			dayName: day.toLocaleString('default', {
				weekday: 'long'
			}),
			dayNumber: day.getDate()
		});
	}

	return weekDays;
}

// 获取今天是星期几
export function getWeekDayOfDate(date) {
	const date = new Date(date);
	// 获取星期几，getDay() 方法返回一个 0（代表星期日）到 6（代表星期六）之间的整数
	const dayOfWeek = date.getDay();
	const daysOfWeek = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
	return daysOfWeek[dayOfWeek];
}

// 判断两个时间是否在某个分钟数之内，默认5分钟
export function isWithinFiveMinutes(arg1, arg2, minutes = 5) {
	//统一按24小时制
	const timeStampTypes = ['Date', 'String', 'Number']
	if (!timeStampTypes.includes(arg1.constructor.name) || !timeStampTypes.includes(arg2.constructor.name)) {
		throw new Error(
			`Type check failed for argument "${date1} or ${date2}".`
		)
	}
	const date1 =
		arg1 instanceof Date ? arg1 : new Date(+arg1);
	const date2 =
		arg2 instanceof Date ? arg2 : new Date(+arg2)


	// 计算两个日期对象之间的毫秒差
	const timeDifference = Math.abs(date1 - date2);

	// 分钟->毫秒
	const fiveMinutesInMilliseconds = minutes * 60 * 1000;

	// 检查时间差是否小于或等于5分钟
	return timeDifference <= fiveMinutesInMilliseconds;
}

// 判断时间是否是今年
export function isThisYear(timeStamp) {
	//统一按24小时制
	const timeStampTypes = ['Date', 'String', 'Number']
	if (!timeStampTypes.includes(timeStamp.constructor.name)) {
		throw new Error(
			`Type check failed for argument "${timeStamp}".`
		)
	}
	const date =
		timeStamp instanceof Date ? timeStamp : new Date(+timeStamp)
	// 获取当前年份
	const currentYear = new Date().getFullYear();

	// 获取给定日期的年份
	const dateYear = date.getFullYear();

	// 检查年份是否相同
	return currentYear === dateYear;
}

// 判断时间是否是今天
export function isToday(timeStamp) {
	//统一按24小时制
	const timeStampTypes = ['Date', 'String', 'Number']
	if (!timeStampTypes.includes(timeStamp.constructor.name)) {
		throw new Error(
			`Type check failed for argument "${timeStamp}".`
		)
	}
	const date =
		timeStamp instanceof Date ? timeStamp : new Date(+timeStamp)
	// 获取今天的日期对象，时间部分设置为00:00:00
	const todayStart = new Date();
	todayStart.setHours(0, 0, 0, 0);

	// 获取今天的日期对象，时间部分设置为23:59:59
	const todayEnd = new Date();
	todayEnd.setHours(23, 59, 59, 999);

	// 检查给定的日期是否在今天的时间范围内
	return date >= todayStart && date <= todayEnd;
}

// 获取上个月第一天和最后一天
export function getLastMonthRange() {
	const now = new Date();
	let year = now.getFullYear();
	let month: any = now.getMonth();

	if (month === 0) {
		month = 12;
		year--;
	}
	month = month < 10 ? `0${month}` : month;

	const firstDay = `${year}-${month}-01`;
	const lastDay = `${year}-${month}-${new Date(year, month, 0).getDate()}`;

	return {
		firstDay,
		lastDay
	};
}